﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.WebControls;
using System.Data;
using System.Globalization;
using System.Collections;
using Rtl.SharePoint.VEService;
using Rtl.SharePoint.Administration;

namespace Rtl.SharePoint.WebControls
{
    public class VEAddressLookupQueryControl : SimpleQueryControl
    {
        // Virtual Earth Data Source to use
        const string VE_DS = "MapPoint.NA";     // Virtual Earth North America

        // array of column names shown in the results table
        private string[] columnNames = { "Address", "City", "State", "Zip", "Formatted", "Latitude", "Longitude" };

        public VEAddressLookupQueryControl() : base() { }

        protected override int IssueQuery(string search, string groupName, int pageIndex, int pageSize)
        {
            // validate that there is a search to perform
            if ((string.IsNullOrEmpty(search)) || (search.Trim().Length == 0))
            {
                base.PickerDialog.ErrorMessage = "No query to perform";
                return 0;
            }

            // format the search and create the data set where results will be placed
            search = search.Trim().ToLowerInvariant();
            DataTable resultsTable = CreateDataTable();

            // perform the web service query
            FindResults foundResults = DoWebServiceQuery(BuildLookupAddress(search));

            if (foundResults != null)
            {
                IEnumerator resultEnumerator = foundResults.Results.GetEnumerator();

                try
                {
                    // enumerate over the results and load them into the data table
                    while (resultEnumerator.MoveNext())
                    {
                        FindResult current = (FindResult)resultEnumerator.Current;
                        DataRow newRow = resultsTable.NewRow();
                        newRow[columnNames[0]] = current.FoundLocation.Address.AddressLine;
                        newRow[columnNames[1]] = current.FoundLocation.Address.PrimaryCity;
                        newRow[columnNames[2]] = current.FoundLocation.Address.Subdivision;
                        newRow[columnNames[3]] = current.FoundLocation.Address.PostalCode;
                        newRow[columnNames[4]] = current.FoundLocation.Address.FormattedAddress;
                        newRow[columnNames[5]] = current.FoundLocation.LatLong.Latitude;
                        newRow[columnNames[6]] = current.FoundLocation.LatLong.Longitude;
                        resultsTable.Rows.Add(newRow);
                    }
                }
                finally
                {
                    IDisposable disposable = resultEnumerator as IDisposable;
                    if (disposable != null)
                        disposable.Dispose();
                }
            }

            base.PickerDialog.Results = resultsTable;

            if (resultsTable.Rows.Count == 0)
            {
                base.PickerDialog.ErrorMessage = "The address could not be validated.";
            }

            base.PickerDialog.ResultControl.PageSize = resultsTable.Rows.Count;
            return resultsTable.Rows.Count;
        }

        public override PickerEntity GetEntity(DataRow dr)
        {
            if (dr == null)
                return null;

            PickerEntity entity = new PickerEntity();
            entity.Key = dr[columnNames[4]].ToString();
            entity.IsResolved = true;
            entity.DisplayText = dr[columnNames[4]].ToString();
            entity.Description = dr[columnNames[4]].ToString();

            IEnumerator columnEnumerator = columnNames.GetEnumerator();

            try
            {
                while (columnEnumerator.MoveNext())
                {
                    string current = (string)columnEnumerator.Current;
                    entity.EntityData.Add(current, dr[current]);
                }
            }
            finally
            {
                IDisposable disposable = columnEnumerator as IDisposable;
                if (disposable != null)
                    disposable.Dispose();
            }

            return entity;
        }

        /// <summary>
        /// Creates an empty DataTable where the results will be placed.
        /// </summary>
        /// <returns></returns>
        private DataTable CreateDataTable()
        {
            DataColumn newColumn = null;
            DataTable table = new DataTable();
            table.Locale = System.Globalization.CultureInfo.InvariantCulture;

            /* generate columns for those specified by the picker dialog */
            IEnumerator columnEnumerator = ((TableResultControl)base.PickerDialog.ResultControl).ColumnNames.GetEnumerator();
            try
            {
                while (columnEnumerator.MoveNext())
                {
                    string current = (string)columnEnumerator.Current;
                    newColumn = new DataColumn(current, typeof(string));
                    table.Columns.Add(newColumn);
                }
            }
            finally
            {
                IDisposable disposable = columnEnumerator as IDisposable;
                if (disposable != null)
                    disposable.Dispose();
            }

            /* generate table columns for address fields */
            columnEnumerator = columnNames.GetEnumerator();

            try
            {
                while (columnEnumerator.MoveNext())
                {
                    string current = (string)columnEnumerator.Current;

                    if (!table.Columns.Contains(current))
                    {
                        newColumn = new DataColumn(current, typeof(string));
                        table.Columns.Add(newColumn);
                    }
                }
            }
            finally
            {
                IDisposable disposable = columnEnumerator as IDisposable;
                if (disposable != null)
                    disposable.Dispose();
            }

            return table;
        }

        /// <summary>
        /// Perform a query against the virtual earth web service to perform address validation.
        /// </summary>
        /// <param name="lookupAddress">Address information to search for.</param>
        /// <returns>Results of the service query.</returns>
        private FindResults DoWebServiceQuery(Address lookupAddress)
        {
            VEConnectionInfoStorage storageHelper = new VEConnectionInfoStorage();
            VEConnectionInfo connectionSettings = storageHelper.Settings;
            
            // establish a conection with the virtual earth web service
            FindServiceSoap findService = new FindServiceSoap();
            findService.Url = connectionSettings.ServiceUrl;
            findService.Credentials = new System.Net.NetworkCredential(connectionSettings.AccountID, connectionSettings.Password);

            // create the query object
            FindAddressSpecification findAddressSpec = new FindAddressSpecification();
            findAddressSpec.InputAddress = lookupAddress;
            findAddressSpec.DataSourceName = VE_DS;

            try
            {
                // query for matching addresses
                FindResults foundAddressResults = findService.FindAddress(findAddressSpec);
                return foundAddressResults;
            }
            catch
            {
                // an error occured
                return null;
            }
        }

        /// <summary>
        /// converts the search string into a Virtual Earth Address object.
        /// </summary>
        /// <param name="search">search string from the dialog.</param>
        /// <returns>A Virtual Earth Address object.</returns>
        private Address BuildLookupAddress(string search)
        {
            Address lookupAddress = new Address();
            lookupAddress.FormattedAddress = search;
            return lookupAddress;
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            base.ColumnList.Visible = false;
        }
    }
}
